home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / EmacsTeX / Emacs-3.0.1 / Source / etermSupport.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-12  |  7.2 KB  |  273 lines

  1. /* Supporting c code for the EtermView class.
  2.  
  3.    For legal stuff see the file COPYRIGHT.  */
  4.  
  5. #include <libc.h>
  6. #include <appkit/nextstd.h>
  7. #include <errno.h>
  8. #include <netdb.h>
  9. #include <netinet/in.h>
  10. #include <signal.h>
  11. #include <stdio.h>
  12. #include <sys/types.h>
  13. #include <sys/ioctl.h>
  14. #include <sys/wait.h>
  15. #include <sys/socket.h>
  16.  
  17. #include "defaults.h"
  18. #include "etermSupport.h"
  19.  
  20. /* Some random lab's phone number.  Ask Tom Lord.  */
  21. #define FIB20 6765
  22.  
  23. extern int errno;
  24.  
  25. /* Given the current environment, give us a new environment suitable for an
  26.    emacs process with an event server on port 'eventportno' */
  27. char **
  28. patch_env (char **currentEnv, int eventportno)
  29. {
  30.   static char term[] = "TERM=eterm";
  31.   static char termcap[] = "TERMCAP=69|eterm|Terminal emulator for Gnu-emacs:co#80:li#24:cm=^u%d^u%d.:IC=^u%d_:DC=^u%d^d:AL=^u%d^o:DL=^u%d^k:bc=^b:bl=^g:cd=^[k:ce=^k:ch=^u%d.:cl=^[c:cr=^a:do=^n:im=^i:ei=^i:le=^b:mi:ms:nd=^f:nl=^j:se=^s:so=^s:up=^p:am:km:";
  32.   char *eventhost;
  33.   static char eventport[80];
  34.   char **newEnv;
  35.   int envSize, x, y;
  36.   char hostname[1024];
  37.  
  38.   if (gethostname (hostname, sizeof (hostname)) == -1)
  39.     {
  40.       NXLogError ("gethostname: %s", strerror (errno));
  41.       exit (1);
  42.     }
  43.  
  44.   eventhost = malloc (strlen (hostname) + 12);
  45.   strcpy (eventhost, "EVENT_HOST=");
  46.   strcat (eventhost, hostname);
  47.  
  48.   sprintf (eventport, "EVENT_PORT=%d", eventportno);
  49.  
  50.   for (envSize = 0; currentEnv[envSize] != NULL; envSize++);
  51.   newEnv = (char **) malloc (sizeof (char *) *(envSize + 5));
  52.   for (x = y = 0; x < envSize; x++)
  53.     if (strncmp (currentEnv[x], "TERM=", 5)
  54.     && strncmp (currentEnv[x], "TERMCAP=", 8)
  55.     && strncmp (currentEnv[x], "EVENT_HOST=", 11)
  56.     && strncmp (currentEnv[x], "EVENT_PORT=", 11))
  57.       newEnv[y++] = currentEnv[x];
  58.   newEnv[y++] = term;
  59.   newEnv[y++] = termcap;
  60.   newEnv[y++] = eventhost;
  61.   newEnv[y++] = eventport;
  62.   newEnv[y] = NULL;
  63.   return newEnv;
  64. } /* patch_env */
  65.  
  66. /* Create the event server socket for an emacs process.  Store the port
  67.    number in the int ponted to by eventportno.  */
  68. int
  69. create_server_socket (int *eventportno)
  70. {
  71.   int EventServerSocket;
  72.   struct sockaddr_in name;
  73.   int portno = FIB20;
  74.  
  75.   if ((EventServerSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  76.     {
  77.       NXLogError ("socket: %s", strerror (errno));
  78.       exit (1);
  79.     }
  80.  
  81.   while (portno < FIB20 + 100)
  82.     {
  83.       name.sin_family = AF_INET;
  84.       name.sin_port = htons (portno);
  85.       name.sin_addr.s_addr = INADDR_ANY;
  86.  
  87.       if (bind (EventServerSocket, (struct sockaddr *) &name, sizeof (name))
  88.       == -1)
  89.     {
  90.       portno++;
  91.       continue;
  92.     }
  93.       if (listen (EventServerSocket, 1) == -1)
  94.     {
  95.       NXLogError ("listen: %s", strerror (errno));
  96.       exit (1);
  97.     }
  98.       *eventportno = portno;
  99.       return EventServerSocket;
  100.     }
  101.   NXLogError ("bind: %s", strerror (errno));
  102.   exit (1);
  103. } /* create_server_socket */
  104.  
  105. /* Accept a connection on an event server socket.  */
  106. int
  107. accept_server_connection (int serversocket)
  108. {
  109.   int s;
  110.   struct sockaddr_in name;
  111.   int namelen = sizeof (name);
  112.  
  113.   if ((s = accept (serversocket, (struct sockaddr *) &name, &namelen)) == -1)
  114.     return -1;
  115.   return s;
  116. } /* accept_server_connection */
  117.  
  118. /* The create_channel code is stolen from h19.  "it should be replaced".  */
  119. char  ptcname[] = "/dev/ptyXX";
  120. char  ptyname[] = "/dev/ttyXX";
  121.  
  122. /* Grab a pty/tty pair for running a child emacs process.  */
  123. void
  124. create_channel (int *master, int *slave, int *ptynumber)
  125. {
  126.   int MasterChannel, PtyNumber, ShellChannel = -1;
  127.   int pid;
  128.   char c;
  129.  
  130.   pid = getpid ();
  131.   if (setpgrp (0, pid) < 0)
  132.     NXLogError ("setpgrp: %s", strerror (errno));
  133.  
  134.   /* Remove the current controling terminal -- will create a new one.  */
  135.   {
  136.     int   fd;
  137.     fd = open ("/dev/tty", 2);
  138.     if (fd >= 0)
  139.       {
  140.     if (ioctl (fd, TIOCNOTTY, NULL) < 0)
  141.       NXLogError ("ioctl (TIOCNOTTY): %s", strerror (errno));
  142.     close (fd);
  143.       }
  144.   }
  145.  
  146.   /* Find pseudo-teletype for subchannel to shell.  */
  147.   for (c = 'p'; c <= 'r'; c++)
  148.     {
  149.       ptcname[strlen ("/dev/pty")] = c;
  150.       ptcname[strlen ("/dev/ptyX")] = '0';
  151.       for (PtyNumber = 0; PtyNumber < 16; PtyNumber++)
  152.     {
  153.       ptcname[strlen ("/dev/ptyX")] = "0123456789abcdef"[PtyNumber];
  154.       MasterChannel = open (ptcname, 2);
  155.       if (MasterChannel < 0)
  156.         continue;
  157.       ptyname[strlen ("/dev/tty")] = c;
  158.       ptyname[strlen ("/dev/ttyX")] = "0123456789abcdef"[PtyNumber];
  159.       ShellChannel = open (ptyname, 2);
  160.       if (ShellChannel >= 0)
  161.         goto gotpty;
  162.       close (MasterChannel);
  163.     }
  164.     }
  165.  
  166.  gotpty:
  167.   if (MasterChannel < 0 || ShellChannel < 0)
  168.     {
  169.       NXLogError ("Can't connect subchannel");
  170.       exit (1);
  171.     }
  172.  
  173.   /* Adjust terminal driver for Master Channel.  */
  174.   {
  175.     int     nonBlock = 1;
  176.     /* Exclusive use of Master.  */
  177.     if (ioctl (MasterChannel, FIOCLEX, NULL) < 0)
  178.       NXLogError ("ioctl (FIOCLEX): %s", strerror (errno));
  179.     if (ioctl (MasterChannel, FIONBIO, &nonBlock) < 0)
  180.       NXLogError ("ioctl (FIONBIO): %s", strerror (errno));
  181.   }
  182.  
  183.   /* Adjust terminal driver for Shell Channel.  */
  184.   {
  185.     int line_discipline = NTTYDISC;
  186.     int local_mode;
  187.     struct sgttyb  ttystate;
  188.  
  189.     if (ioctl (ShellChannel, TIOCHPCL, NULL) < 0)
  190.       perror ("TIOCHPCL");
  191.     if (ioctl (ShellChannel, TIOCSETD, &line_discipline) < 0)
  192.       perror ("TIOCSETD");
  193.     if (ioctl (ShellChannel, TIOCGETP, &ttystate) < 0)
  194.       perror ("TIOCGETP");
  195.     ttystate.sg_flags = CRMOD | ANYP | ECHO;
  196.  
  197.     /* CRMOD - tread CR like LF; output of LF is CR/LF 
  198.        XTABS - change TABS to sequence of blanks 
  199.        ANYP - Any parity okay
  200.        ECHO - echo characters (full duplex)  */
  201.     ttystate.sg_erase = '\010';
  202.     if (ioctl (ShellChannel, TIOCSETP, &ttystate) < 0)
  203.       perror ("TIOCSETP");
  204.     if (ioctl (ShellChannel, TIOCLGET, &local_mode) < 0)
  205.       perror ("TIOCLGET");
  206.  
  207.     /* LCRTBS - CRT back space to ^H
  208.        LCRTERA - backspace-space-backspace
  209.        LCRTKIL - erase as LCRTERA for line kill too
  210.        LCTLECH - echo non-printing characters as ^X.  */
  211.     local_mode |= LCRTBS | LCRTKIL | LCRTERA | LCTLECH;
  212.     if (ioctl (ShellChannel, TIOCLSET, &local_mode) < 0)
  213.       perror ("TIOCLSET");
  214.   }
  215.   *master = MasterChannel;
  216.   *slave = ShellChannel;
  217.   *ptynumber = PtyNumber;
  218. } /* create_channel */
  219.  
  220. /* Reap zombie processes.  If any child processes stopped themselves, give
  221.    them a kick in the pants.  */
  222. static void
  223. ShellDone ()
  224. {
  225.   int pid;
  226.   union wait stat;
  227.  
  228.   while ((pid = wait3 (&stat, WUNTRACED | WNOHANG, 0 )) > 0)
  229.     {
  230.       if (WIFSTOPPED (stat))
  231.     kill (pid,SIGCONT);
  232.     }
  233. } /* ShellDone */
  234.  
  235. /* Fork and exec the child emacs.  */
  236. void
  237. fork_shell (char *name, char **args, char **env, int channel)
  238. {
  239.   int pid;
  240.  
  241.   signal (SIGCLD, ShellDone);
  242.   signal (SIGTTOU, SIG_IGN);
  243.  
  244.   if ((pid = fork ()) < 0)
  245.     {
  246.       NXLogError ("fork: %s", strerror (errno));
  247.       exit (1);
  248.     }
  249.  
  250.   if (pid == 0)
  251.     {
  252.       int i;
  253.       int cpid;
  254.  
  255.       cpid = getpid ();
  256.       if (ioctl (channel, TIOCSPGRP, &cpid) < 0)
  257.     perror ("TIOCSPGRP");
  258.       if (setpgrp (0, cpid) < 0)
  259.     perror ("setpgrp");
  260.  
  261.       dup2 (channel, 0);
  262.       dup2 (channel, 1);
  263.       for (i = getdtablesize (); i > 2; i--)
  264.     close (i);
  265.  
  266.       execve (name, args, env);
  267.       NXLogError ("%s: %s", name, strerror (errno));
  268.       execve (DEFAULT_EMACS_PATH, args, env);
  269.       NXLogError ("%s: %s", DEFAULT_EMACS_PATH, strerror (errno));
  270.       exit (1);
  271.     }
  272. } /* fork_shell */
  273.